﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;
using System.Collections;
using System.Diagnostics;

namespace ZoomEngine.Util
{
    public class CopyOnWriteCollection<T> : IList<T> 
    {
        public ReadOnlyCollection<T> Open()
        {
            EnsureList();

            _openedCount++;
            if (_readOnlyList == null)
            {
                _readOnlyList = new ReadOnlyCollection<T>(_list);
            }

            return _readOnlyList;
        }

        public void Close()
        {
            if (_openedCount < 1)
            {
                throw new InvalidOperationException("Collection not opened.");
            }

            if (--_openedCount == 0 && _hasCopied)
            {
                _hasCopied = false;
                _readOnlyList = null;
            }
        }

        private void EnsureList()
        {
            if (_list == null)
            {
                _list = CreateInternalList(null);
            }

 	        if (_openedCount > 0 && !_hasCopied)
            {
                Debug.Assert(_readOnlyList != null, "_readOnlyList should be created");
                _list = CreateInternalList(_readOnlyList);
                _hasCopied = true;
            }
        }

        protected virtual IList<T> CreateInternalList(IList<T> list)
        {
            if (list == null)
            {
                return new List<T>();
            }
            else
            {
                return new List<T>(list);
            }
        }

        #region IList<T> Members

        public int IndexOf(T item)
        {
            EnsureList();
            return _list.IndexOf(item);
        }


        public void Insert(int index, T item)
        {
            EnsureList();
            _list.Insert(index, item);
        }

        public void RemoveAt(int index)
        {
            EnsureList();
            _list.RemoveAt(index);
        }

        public T this[int index]
        {
            get
            {
                EnsureList();
                return _list[index];
            }
            set
            {
                EnsureList();
                _list[index] = value;
            }
        }

        #endregion

        #region ICollection<T> Members

        public void Add(T item)
        {
            EnsureList();
            _list.Add(item);
        }

        public void Clear()
        {
            EnsureList();
            _list.Clear();
        }

        public bool Contains(T item)
        {
            EnsureList();
            return _list.Contains(item);
        }

        public void CopyTo(T[] array, int arrayIndex)
        {
            EnsureList();
            _list.CopyTo(array, arrayIndex);
        }

        public int Count
        {
            get 
            {
                EnsureList();
                return _list.Count;
            }
        }

        public bool IsReadOnly
        {
            get { return false; }
        }

        public bool Remove(T item)
        {
            EnsureList();
            return _list.Remove(item);
        }

        #endregion

        #region IEnumerable<T> Members

        public IEnumerator<T> GetEnumerator()
        {
            EnsureList();
            return _list.GetEnumerator();
        }

        #endregion

        #region IEnumerable Members

        IEnumerator IEnumerable.GetEnumerator()
        {
            EnsureList();
            return ((IEnumerable)_list).GetEnumerator();
        }

        #endregion

        protected IList<T> InternalList
        {
            get
            {
                return _list;
            }
        }

        int _openedCount;
        bool _hasCopied;
        ReadOnlyCollection<T> _readOnlyList;
        IList<T> _list;
    }
}
